<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://unpkg.com/vue@2"></script>
</head>
<body>
  <div id="app">
    <h1 class="title">{{ message }}</h1>
    <br/>
    <button class="btn" v-clickoutside.2000="handleClickout">点击按钮外部延迟2s</button>
  </div>
</body>
<style>
  .title {
    border-bottom: 1px solid #eee;
    padding: 20px 0;
  }
  .btn {
    border-radius: 0px;
    outline: 0px;
    border: 1px solid #666;
    padding: 6px 10px;
  }
</style>
<script>
  /**
   * 实现一个v-clickoutside指令
   * <button v-clickoutside.2000="handleClickout"></button>
   * 点击目标区域外部执行，2000表示延迟2000ms执行点击事件
  */
  Vue.directive('clickoutside', {
    bind(el, binding, vnode) {
      const delay = Number(Object.keys(binding.modifiers)[0]) || 0 
      el.clickoutTimerId = null;

      el.clickOutsideEvent = function (e) {
        if (!(el === e.target || el.contains(e.target))) {
          if (el.clickoutTimerId) clearTimeout(el.timerId)
          el.clickoutTimerId = setTimeout(() => binding.value(e), delay)
        }
      }

      document.addEventListener('click', el.clickOutsideEvent)
    },
    unbind(el) {
      document.removeEventListener('click', el.clickOutsideEvent)
      clearTimeout(el.clickoutTimerId)
    }
  })
 var app = new Vue({
  el: '#app',
  data: {
    message: '点击目标元素外部延迟执行指令',
  },
  methods:{
    handleClickout() {
      alert('点击了按钮外部')
    }
  },
 })
</script>
</html>
